package com.song.boot.springstudy.ms.szjz.al5;

import lombok.Data;
import lombok.SneakyThrows;
import lombok.ToString;
import org.apache.commons.lang3.time.StopWatch;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.stream.Collectors;

public class PriceFetcher_02 {
    // 线程池大小设为5，匹配第三方接口每秒处理5个请求的能力
    private static final ExecutorService executor = Executors.newFixedThreadPool(5);
    private static final Random random = new Random();

    public static List<PackData> fetchPrices(List<Long> times) throws InterruptedException, ExecutionException {
        List<CompletableFuture<PackData>> futures = new ArrayList<>();


        for (int i = 0; i < times.size(); i++) {
            int finalI = i;
            CompletableFuture<PackData> future = CompletableFuture.supplyAsync(() -> {
                long startTime = System.currentTimeMillis();
                double price = callThirdPartyAPI(times.get(finalI));
                long endTime = System.currentTimeMillis();
                PackData data = new PackData();
                data.setIndex(finalI);
                data.setData(price);
                data.setMs(endTime - startTime);
                data.setSuccess(true);
                return data;
            }, executor);
            futures.add(future);
        }
         CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        try {
            // 等待所有任务完成或5秒超时
            voidCompletableFuture.get(5, TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            // 超时异常不做处理，继续收集已完成的结果
        }
        final List<PackData> collect = futures.stream().filter(CompletableFuture::isDone).map(future -> {
            try {
                return future.get();
            } catch (Exception e) {
                return null;
            }
        }).filter(data -> data.isSuccess() && data != null).collect(Collectors.toList());

        return collect;
    }

    // 模拟第三方API调用
    @SneakyThrows
    private static double callThirdPartyAPI(long time) {
        // 模拟网络延迟 (100ms ~ 4099ms)
        int delay = 100 + random.nextInt(5000);
        Thread.sleep(delay);

        // 生成随机价格作为模拟结果
        return Double.parseDouble(String.format("%.2f", random.nextDouble() * 100));
    }

    public static void main(String[] args) {
        try {
            PriceFetcher_02 fetcher = new PriceFetcher_02();

            // 创建10个时间参数
            List<Long> times = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                times.add(System.currentTimeMillis() + i * 1000);
            }

            StopWatch stopWatch = StopWatch.createStarted();
            List<PackData> results = fetcher.fetchPrices(times);
            stopWatch.stop();

            System.out.println("执行时间: " + stopWatch.getTime() + " 毫秒");
            System.out.println("成功获取 " + results.size() + " 个价格:");
            results.forEach(System.out::println);

            executor.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Data
    @ToString
    static class PackData {
        private int index;
        private double data;
        private long ms;
        private boolean success;
    }
}
